/*
 * Copyright (c) Huawei Device Co., Ltd. 2023. All rights reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "reader_impl.h"
#include "loghelper.h"
#include "se_common_exception.h"
#include "service_manager.h"
#include "service_impl.h"
#include "session_impl.h"
#include "secure_element_agent.h"
#include "se_hianalytics.h"

namespace OHOS {
namespace SE {
ReaderImpl::ReaderImpl(std::weak_ptr<SecureElementAgent> agent)
    : boundHdfAgent_(agent), openSessions_({})
{
}

ReaderImpl::~ReaderImpl()
{
    InfoLog("ReaderImpl::~ReaderImpl");
    std::lock_guard<std::mutex> lock(mutex_);
    openSessions_.clear();
}

std::weak_ptr<SecureElementAgent> ReaderImpl::GetSecureElementAgent()
{
    // don't lock for mutex_, GetSecureElementAgent called by other module.
    return boundHdfAgent_;
}

ErrorCode ReaderImpl::IsSecureElementPresent(bool& isPresent)
{
    std::lock_guard<std::mutex> lock(mutex_);
    if (boundHdfAgent_.expired()) {
        WarnLog("IsSecureElementPresent invalid state.");
        isPresent = false;
        SeHiAnalytics::GetInstance().SeEventLog(LOG_SECURE_ELEMENT_NO_PRESENT, LOG_DEFAULT_STR);
        return ErrorCode::SE_ILLEGAL_STATE_ERROR;
    }
    isPresent = boundHdfAgent_.lock()->IsSecureElementPresent();
    return ErrorCode::SE_SUCCESS;
}

ErrorCode ReaderImpl::OpenSession(sptr<OMAPI::ISecureElementSession>& session)
{
    bool isPresent = false;
    IsSecureElementPresent(isPresent);
    if (!isPresent) {
        WarnLog("OpenSession invalid state.");
        SeHiAnalytics::GetInstance().SeEventLog(LOG_READER_NULL, LOG_DEFAULT_STR);
        session = nullptr;
        return ErrorCode::SE_ILLEGAL_STATE_ERROR;
    }

    std::lock_guard<std::mutex> lock(mutex_);
    if (!session) {
        InfoLog("OpenSession:: new SessionImpl.");
        session = new SessionImpl(this);
    } else {
        ErrorLog("OpenSession:: session is not null before new SessionImpl.");
        return ErrorCode::SE_ILLEGAL_STATE_ERROR;
    }
    openSessions_.push_back(session);
    return ErrorCode::SE_SUCCESS;
}

ErrorCode ReaderImpl::CloseSessions(void)
{
    InfoLog("ReaderImpl::CloseSessions start.");
    bool isPresent = false;
    ErrorCode ret = IsSecureElementPresent(isPresent);
    if (ret != ErrorCode::SE_SUCCESS || !isPresent) {
        ErrorLog("CloseSessions invalid state.");
        return ErrorCode::SE_ILLEGAL_STATE_ERROR;
    }
    std::lock_guard<std::mutex> lock(mutex_);
    if (openSessions_.size() == 0) {
        WarnLog("CloseSessions already empty.");
        return ErrorCode::SE_SUCCESS;
    }

    std::vector<sptr<OMAPI::ISecureElementSession>>::iterator iter = openSessions_.begin();
    while (iter != openSessions_.end()) {
        // close for each session.
        ret = (*iter)->Close();
        InfoLog("ReaderImpl::CloseSessions Close ret %{public}d", ret);
        ++iter;
    }
    openSessions_.clear();
    InfoLog("ReaderImpl::CloseSessions done.");
    return ret;
}

ErrorCode ReaderImpl::Reset(bool& resetStatus)
{
    bool isPresent = false;
    ErrorCode ret = IsSecureElementPresent(isPresent);
    if (ret != ErrorCode::SE_SUCCESS || !isPresent) {
        ErrorLog("Reset invalid state.");
        resetStatus = false;
        return ErrorCode::SE_ILLEGAL_STATE_ERROR;
    }

    std::lock_guard<std::mutex> lock(mutex_);
    if (boundHdfAgent_.expired()) {
        resetStatus = false;
        return ErrorCode::SE_ILLEGAL_STATE_ERROR;
    }
    resetStatus = boundHdfAgent_.lock()->Reset();
    return ret;
}

std::string ReaderImpl::GetAtr()
{
    bool isPresent = false;
    ErrorCode ret = IsSecureElementPresent(isPresent);
    if (ret != ErrorCode::SE_SUCCESS || !isPresent) {
        ErrorLog("GetAtr invalid state.");
        SeHiAnalytics::GetInstance().SeEventLog(LOG_GET_ATR_NULL, LOG_DEFAULT_STR);
        return std::string();
    }
    std::lock_guard<std::mutex> lock(mutex_);
    if (boundHdfAgent_.expired()) {
        SeHiAnalytics::GetInstance().SeEventLog(LOG_GET_ATR_NULL, LOG_DEFAULT_STR);
        return std::string();
    }
    std::string retStr = boundHdfAgent_.lock()->GetAtr();
    if (retStr.empty()) {
        SeHiAnalytics::GetInstance().SeEventLog(LOG_GET_ATR_NULL, LOG_DEFAULT_STR);
    }
    return retStr;
}
}  // namespace SE
}  // namespace OHOS